#ifndef _THREAD_H_
#define _THREAD_H_

#include <sys/type.h>
#include <stdio.h>

#define _DEBUG_THREAD	1

#define trace(str) printf("[%s] -- %s\n", __FUNCTION__, str)

#define MAX_WAIT_INTERVAL					5    //the max wait time in seconds
#define LEN_THREAD_NAME						16

#define THREAD_INIT_HEARTBEATS				2
#define THREAD_MANAGER_HEARTBEAT_INTERVAL	500
#define THREAD_HEARTBEAT_CHECK_INTERVAL		300000

typedef void *(*PTHREAD_START_ROUTE)(void *);

#if (THREAD_HEARTBEAT_CHECK_INTERVAL < (2*MAX_WAIT_INTERVAL*1000))
#error The Value "THREAD_HEARTBEAT_CHECK_INTERVAL" is too small!
#endif

enum _THRAED_EVENT_ENUM
{
	THREAD_EVENT_HEARTBEAT				=	1,	//the heartbeat event from thread
	THREAD_EVENT_NO_RESPONSE			=	2,	//the thread is no response event
	THREAD_EVENT_MANAGER_HAS_STARTED	=	3,
	THREAD_EVENT_CANNOT_BE_STOPPED		=	4,
	THREAD_EVENT_MANAGER_HAS_STOPPED	=	5
};

typedef struct _THREAD_ENTRY
{
	//hiword is a magic word, low worod is the index in thread 
	//manager
	DWORD			dwThreadId;
	char			szThreadName[LEN_THREAD_NAME];
	pthread_t		hSystemThread;
	void 			*pMsgQueue;
	DWORD volatile	dwThreadHeartBeat;
	int volatile	nStatus;	
} THREAD_ENTRY;


typedef struct _THREAD_START_ARG
{
	THREAD_ENTRY 		*pThreadEntry;
	void 				*hThread;
	THREAD_START_FUNC	pThreadFunc;
	void				*pThreadArg;
	DWORD				*pdwExitCode;
	pthread_mutex_t		hSyncLock;
} THREAD_START_ARG;

typedef struct _THREAD_MANAGER //the running thread manager
{
	int						nThreadEntries;
	THREAD_ENTRY			*pThreadEntries;
	int volatile			nRuningThreads;
	THREAD_EVENT_HANDLER	pThreadEventHandlerFunc;
	pthread_mutex_t			hSyncLock;  //lock to protect the entry
	int						nLastEmptyEntry;
	pthread_t				hManagerThread;
	int volatile			nStatus;
} THREAD_MANAGER;


#define THREAD_CONTINUE_RUN	0
#define THREAD_CANCEL_THIS	1
#define THREAD_CANCEL_ALL	2

/*=========================================================================
 *FUNCTION	:	THREAD_START_FUNC
 *PURPOSE	:	THE RUN THREAD ENTRY ROUTE
 *CALLS		:
 *CALL BY	:
 *ARGUMENTS	:	void* pArgs //the arg to run the thread
 *RETURN	:	eixt code of the thread. 0 is normal
 *=========================================================================*/
typedef DWORD (*THREAD_START_FUNC)(void *pArgs);

/*=========================================================================
 *FUNCTION	:	THREAD_EVENT_HANDLER
 *PURPOSE	:	handler to process the event comes from thread manager	
 *CALLS		:
 *CALL BY	:
 *ARGUMENTS	:	dwThreadEvent	: THREAD_EVENT_HEARTBEAT OR THREAD_EVENT_NO_RESPONES
 				hThread			: the thread ID
 *RETURN	:	THREAD_CONTINUE_RUN, THREAD_CANCEL_THIS or THREAD_CANCEL_ALL
 *=========================================================================*/
typedef DWORD (*THREAD_EVENT_HANDLER)
(
 DOWRD dwThreadEvent, 
 void* hThread, 
 const char *pThreadName
);

/*=========================================================================
 *FUNCTION	:	Thread_Create
 *PURPOSE	:	create a detached thread	
 *CALLS		:	pthread API
 *CALL BY	:
 *ARGUMENTS	:	pThreadName		: THREAD_EVENT_HEARTBEAT OR THREAD_EVENT_NO_RESPONES
 				pFunc			: the main proc of thread 
				arg				: arg of the thread
				pdwExitCode		: ptr to save exit code. can be null. if not null, the addr
								  must be keep valid when the thread is running
				dwCreateFlag	: create flags. 0 for no flags
 *RETURN	:	null for failure. success for the ptr of thread	
 *=========================================================================*/
void * Thread_Create(const char * pThreadName,
					THREAD_START_FUNC pFunc, 
					void * arg,
					DWORD * pdwExitCode,
					DWORD dwCreateFlag);

#define THREAD_FLAG_HAS_MSG_QUEUE 0X0001 //a msg queue will be create
#define THREAD_FLAG_HAS(flags,f) ((((int)(flags))&((int)(f)))==((int)(f)))

/*=========================================================================
 *FUNCTION	:	Thread_GetId
 *PURPOSE	:	Get the running thread id by name, if name is null will get 
 				the id of this caller thread	
 *CALLS		:	
 *CALL BY	:
 *ARGUMENTS	:	pThreadName		: name of the thread, null for the caller itself.
 				pThreadManager	: thread manager
 *RETURN	:	thread Id
 *=========================================================================*/
const void * Thread_GetId(THREAD_MANAGER *pThreadManager, const char * pThreadName);


/*=========================================================================
 *FUNCTION	:	Thread_GetName
 *PURPOSE	:	Get the running thread name by id, if id is nul, get the itself name	
 *CALLS		:	
 *CALL BY	:
 *ARGUMENTS	:	hThread : null to get self name
 				pThreadManager	: thread manager

 *RETURN	:	thread name, empty string ("", not null) for error
 *=========================================================================*/
char * Thread_GetName(THREAD_MANAGER *pThreadManager, 
					  void * hThread, 
					  char *pName, 
					  int nNameLen);


/*========================================================================
 *
 *Thread Message Definition
 *
 * =======================================================================*/

typedef struct _THREAD_MSG
{
	DWORD dwMsgType;//msg type
	DWORD dwParam1; //the param 1 of the msg
	DWORD dwParam2; //the param 2 of the msg
	void * Sender;  //the thread id of the sender
} THREAD_MSG;


#define THREAD_MAKE_MSG(pMsg, msgType, param1, param2, sender) \
	do { \
		pMsg->dwMsgType = dwMsgType; \
		pMsg->dwParam1 = param1; \
		pMsg->dwParam2 = param2; \
		pMsg->sender = sender; \
	}while(0)


#define DEF_THREAD_MSG(msgType, param1, param2, sender) \
	{ \
		(DWORD)msgType, \
		(DWORD)param1, \
		(DWORD)param2, \
		(void*)sender \
	}

enum THREAD_MSG_TYPE
{
	MSG_QUIT	=	1,
	MSG_TIMER	=	2,
	MSG_MAX_SYS	=	1000,  //the maxumum system msg
	MSG_USER	=	MSG_MAX_SYS
};

#define THREAD_MAX_MSG 500  //the maximum msg can be hold in each thread


/*=========================================================================
 *FUNCTION	:	Thread_GetMessage
 *PURPOSE	:	Get a message from a running thread	
 *CALLS		:	
 *CALL BY	:
 *ARGUMENTS	:	hThread : null to get self name
 				pMsg	: store the msg
				nPeek	: not zero is peek only
				deTimeout : if no msg, the time is ms will wait
 *RETURN	:	ERR_OK for get a msg, ERR_THREAD_INVALID_ID for an invalid 
 				hThread pass in. ERR_THREAD_MSG_EMPTY for no msg
 *=========================================================================*/
int Thread_GetMessage(void * hThread, 
					  THREAD_MSG *pMsg, 
					  int nPeek, 
					  DWORD dwTimeout);


//status of the thread

#define THREAD_IS_RUNNING 0
#define THREAD_TO_QUIT    1
#define THREAD_IS_INVALID 2

/*=========================================================================
 *FUNCTION	:	Thread_GetStatus
 *PURPOSE	:	Get the running state of a thread	
 *CALLS		:	
 *CALL BY	:
 *ARGUMENTS	:	hThread : 
 *RETURN	:	thread status 
 *=========================================================================*/
int Thread_GetStatus(void * hThread);

#define THREAD_IS_RUNNING(hThread) (Thread_GetStatus(hThread)==THREAD_IS_RUNNING)
#define THREAD_IS_QUITED(hThread) (Thread_GetStatus(hThread)==THREAD_IS_INVALID)

/*==========================================================================
 *FUNCTION	:	Thread_GetThreadCount
 *PURPOSE	:	Get the running state of a thread	
 *CALLS		:	
 *CALL BY	:
 *ARGUMENTS	:	 
 *RETURN	:	the thread count 
 *=========================================================================*/
int Thread_GetThreadCount(void);


/*==========================================================================
 *FUNCTION	:	Thread_HeartBeat
 *PURPOSE	:	to trigger atime of heartbeat. a thread would call this func
 *CALLS		:	
 *CALL BY	:
 *ARGUMENTS	:	 
 *RETURN	:	the current heartbeat count 
 *=========================================================================*/
int Thread_HeartBeat(void * hThread);

#define THREAD_HEARTBEAT() Thread_HeartBeat(Thread_GetId(NULL))


/*==========================================================================
 *FUNCTION	:	Thread_PostMessage
 *PURPOSE	:	post a message to given thread
 *CALLS		:	
 *CALL BY	:
 *ARGUMENTS	:	 
 *RETURN	:	ERR_OK for post a msg successfully, ERR_THREAD_INVALID_ID 
 				for an invalid hThread pass in. ERR_THREAD_MSG_FULL for msg
				queue is full
 *=========================================================================*/
int Thread_PostMessage(void * hThread,
					   THREAD_MSG * pMsg,
					   int urgent)


/*==========================================================================
 *FUNCTION	:	Thread_PostQuitMessage
 *PURPOSE	:	post a message to given thread
 *CALLS		:	
 *CALL BY	:
 *ARGUMENTS	:	hThread	: -1 for all threads	 
 *RETURN	:
 *=========================================================================*/
int Thread_PostQuitMessage(void * hThread);


/*==========================================================================
 *FUNCTION	:	Thread_Stop
 *PURPOSE	:	stop a thread	
 *CALLS		:	
 *CALL BY	:
 *ARGUMENTS	:	hThread	: thread id
				nTimeToWaitThreadQuit : wait n ms on thread to quit
				killTimeoutedThread	  : if timeout , kill it
 *RETURN	:   ERR_THREAD_STILL_RUNNING for thread does not stopped,
 				ERR_THREAD_KILLED for thread is terminated by force
 *=========================================================================*/
int Thread_Stop(void * hThread,
				int nTimeToWaitThreadQuit,
				int killTimeoutedThread);


/*==========================================================================
 *FUNCTION	:	Thread_ManagerInit
 *PURPOSE	:	init thread manager	
 *CALLS		:	
 *CALL BY	:
 *ARGUMENTS	:	THREAD_EVENT_HANDLER : pHandlerFunc	
 				pThreadManager
 *RETURN	:  	ERR_OK if OK, else ERR_THREAD_INIT_MANAGER for error 
 *=========================================================================*/
int Thread_ManagerInit(THREAD_MANAGER *pThreadManager,
					   THREAD_EVENT_HANDLER *pHandlerFunc);

/*==========================================================================
 *FUNCTION	:	Thread_ManagerExit
 *PURPOSE	:	exit thread manager	
 *CALLS		:	
 *CALL BY	:
 *ARGUMENTS	:		
 *RETURN	:  	ERR_THREAD_OK if OK, ERR_THREAD_STILL_RUNNING for thread does
				not stopped, ERR_THREAD_KILLED for thread is terminated by 
			    force	
 *=========================================================================*/
int Thread_ManagerExit(THREAD_MANAGER *pThreadManager,
					   int nTimeToWaitThreadQuit,
					   int killTimeoutThread);
#endif
